<?php
namespace common\helpers;

use Exception;

class MemoryLock
{
    private $sem_id;

    private $sem_key;

    public function __construct($name)
    {
        $this->sem_key = $this->mycrc32($name);
    }

    private function mycrc32($string)
    {
        $crc = abs(crc32($string));
        if ($crc & 0x80000000) {
            $crc ^= 0xffffffff;
            $crc += 1;
        }

        return $crc;
    }

    /**
     * 加锁,
     * Enter description here ...
     */
    public function lock()
    {
        try {
            $this->sem_id = sem_get($this->sem_key, 1);
            return sem_acquire($this->sem_id);
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * 解锁
     * Enter description here ...
     */
    public function unlock()
    {
        try {
            sem_release($this->sem_id);
            sem_remove($this->sem_id);
        } catch (Exception $e) {
            //由于并发的原因当A进程刚做完sem_release B进程立刻sem_acquire获得该信号量,此时A进程继续Remove信号量,B进程后续再释放信号量就会出错.
            //但是本质上B进程是合法获取到锁的,所以释放锁的过程不需要抛出异常.
            //该方法还是有一个漏洞:就是当A进程sem_release 信号量后, B 进程sem_acquire占有信号量,
            //然后A进程sem_remove删除信号量,然后C进程sem_get,sem_acquire,创建,占有同一个信号量,导致最终B,C并发.
            //由于是小概率事件.出现问题后,人工修复业务数据.
            //核心是需要一个分布式锁.提供正在的Lock原语.
        }
    }
}
